package io.terminus.lego.shinda.web.security.oauth

import org.springframework.security.oauth2.client.registration.ClientRegistration
import org.springframework.security.oauth2.core.AuthorizationGrantType
import org.springframework.security.oauth2.core.ClientAuthenticationMethod
import org.springframework.security.oauth2.core.oidc.IdTokenClaimNames

/**
 * Oauth2.0的服务提供枚举类
 * 这里可以维护很多第三方账户服务，由于QQ、微博的Oauth2.0协议并不是很规范因此需要代理一下，做一层转换
 * 目前支持：GOOGLE、GITHUB、FACEBOOK、WEIBO、QQ、OKTA
 * @author wangmeng
 * @date 2018/4/21
 */
enum class CustomOAuth2Provider {
    GOOGLE {
        override fun getBuilder(registrationId: String): ClientRegistration.Builder {
            val builder = getBuilder(registrationId,
                    ClientAuthenticationMethod.BASIC, DEFAULT_LOGIN_REDIRECT_URL)
            builder.scope("openid", "profile", "email")
            builder.authorizationUri("https://accounts.google.com/o/oauth2/v2/auth")
            builder.tokenUri("https://www.googleapis.com/oauth2/v4/token")
            builder.jwkSetUri("https://www.googleapis.com/oauth2/v3/certs")
            builder.userInfoUri("https://www.googleapis.com/oauth2/v3/userinfo")
            builder.userNameAttributeName(IdTokenClaimNames.SUB)
            builder.clientName("Google")
            return builder
        }
    },

    GITHUB {
        override fun getBuilder(registrationId: String): ClientRegistration.Builder {
            val builder = getBuilder(registrationId,
                    ClientAuthenticationMethod.BASIC, DEFAULT_LOGIN_REDIRECT_URL)
            builder.scope("read:user")
            builder.authorizationUri("https://github.com/login/oauth/authorize")
            builder.tokenUri("https://github.com/login/oauth/access_token")
            builder.userInfoUri("https://api.github.com/user")
            builder.userNameAttributeName("id")
            builder.clientName("GitHub")
            return builder
        }
    },

    FACEBOOK {
        override fun getBuilder(registrationId: String): ClientRegistration.Builder {
            val builder = getBuilder(registrationId,
                    ClientAuthenticationMethod.POST, DEFAULT_LOGIN_REDIRECT_URL)
            builder.scope("public_profile", "email")
            builder.authorizationUri("https://www.facebook.com/v2.8/dialog/oauth")
            builder.tokenUri("https://graph.facebook.com/v2.8/oauth/access_token")
            builder.userInfoUri("https://graph.facebook.com/me")
            builder.userNameAttributeName("id")
            builder.clientName("Facebook")
            return builder
        }
    },
    TERMINUS {
        override fun getBuilder(registrationId: String): ClientRegistration.Builder {
            val builder = getBuilder(registrationId,
                    ClientAuthenticationMethod.POST, DEFAULT_LOGIN_REDIRECT_URL)
            builder.scope("public_profile", "email")
            builder.authorizationUri("http://localhost:8080/oauth/authorize")
            builder.tokenUri("http://localhost:8080/oauth/token")
            builder.userInfoUri("http://localhost:8080/api/oauth/me")
            builder.userNameAttributeName("id")
            builder.clientAuthenticationMethod(ClientAuthenticationMethod.BASIC)
            builder.clientName("terminus")
            return builder
        }
    },
    WEIBO {
        override fun getBuilder(registrationId: String): ClientRegistration.Builder {
            val builder = getBuilder(registrationId,
                    ClientAuthenticationMethod.POST, DEFAULT_LOGIN_REDIRECT_URL)
            builder.scope("public_profile", "email")
            builder.authorizationUri("https://api.weibo.com/oauth2/authorize")
            builder.tokenUri("http://ucoupon.com:8080/api/proxy/weibo/access-token")
            builder.userInfoUri("http://ucoupon.com:8080/api/proxy/weibo/info")
            builder.userNameAttributeName("id")
            builder.clientAuthenticationMethod(ClientAuthenticationMethod.POST)
            builder.clientName("weibo")
            return builder
        }
    },
    QQ {
        override fun getBuilder(registrationId: String): ClientRegistration.Builder {
            val builder = getBuilder(registrationId,
                    ClientAuthenticationMethod.POST, DEFAULT_LOGIN_REDIRECT_URL)
            builder.scope("public_profile", "email")
            builder.authorizationUri("https://graph.qq.com/oauth2.0/authorize")
            builder.tokenUri("http://ucoupon.com:8080/api/proxy/qq/access-token")
            builder.userInfoUri("http://ucoupon.com:8080/api/proxy/qq/info")
            builder.userNameAttributeName("openid")
            builder.clientAuthenticationMethod(ClientAuthenticationMethod.POST)
            builder.clientName("qq")
            return builder
        }
    },
    OKTA {
        override fun getBuilder(registrationId: String): ClientRegistration.Builder {
            val builder = getBuilder(registrationId,
                    ClientAuthenticationMethod.BASIC, DEFAULT_LOGIN_REDIRECT_URL)
            builder.scope("openid", "profile", "email", "address", "phone")
            builder.userNameAttributeName(IdTokenClaimNames.SUB)
            builder.clientName("Okta")
            return builder
        }
    };

    companion object {
        private val DEFAULT_LOGIN_REDIRECT_URL = "{baseUrl}/login/oauth2/code/{registrationId}"
    }

    protected fun getBuilder(registrationId: String,
                             method: ClientAuthenticationMethod, redirectUri: String): ClientRegistration.Builder {
        val builder = ClientRegistration.withRegistrationId(registrationId)
        builder.clientAuthenticationMethod(method)
        builder.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
        builder.redirectUriTemplate(redirectUri)
        return builder
    }

    /**
     * Create a new
     * [ ClientRegistration.Builder][org.springframework.security.oauth2.client.registration.ClientRegistration.Builder] pre-configured with provider defaults.

     * @param registrationId the registration-id used with the new builder
     * *
     * @return a builder instance
     */
    abstract fun getBuilder(registrationId: String): ClientRegistration.Builder

}
